最近在写一个google / facebook oauth登录系统,前端使用react,后端使用nodejs + express,前后端分别部署在vercel和heroku上,不可避免的遇到很多跨域问题。
今天在将本地代码deploy到生产环境的时候,发现google oauth虽然能成功调用callback url重定向到后端,后端也能设置cookie,但后续的api操作却没有带上之前返回的cookie,导致无法通过api获取用户数据等信息。然而之前在开发环境测试的时候,api操作确实带上了cookie并成功获取数据,并且:
- 在开发和生产环境中后端都设置了
cors({ credentials: true, origin: process.env.CLIENT_BASE_URL })
- 前端axios获取api数据时也设置了
axios.defaults.withCredentials = true;
- 生产环境中前端地址
localhost:3000
和后端地址localhost:5000
同属于跨域,但测试正常
查看console,发现以下错误信息:
1 | A cookie associated with a cross-site resource at http://MYAPI.URL was set |
搜索后发现,该错误是由于chrome等浏览器最近的安全升级导致,该升级要求所有跨域cookie操作都必须要对cookie设置为samesite="none"
和secure="true"
,而且该升级只针对于host不同的情况,其余跨域诸如端口号等不受到影响,这也解释了为什么开发环境测试通过而生产环境出现错误。 MDN参考
后续设置express-session
1 | const sessionConfig = { |
修改后新问题又来了,这次后端直接不设置cookie了,即response中不包含set-cookie。查阅文档后发现当设置cookie为secure时,需要通过https设置cookie,使用http将默认不设置cookie。因此express加多一行代码
1 | app.set('trust proxy', 1) // trust first proxy |
这次在生产环境测试成功,但生产环境的前后端地址都是由第三方提供的https地址,不知道为何也会出现这样的问题,猜想可能需要自行配置有效证书。
Update on 2020-09-21
上述问题其实是由于苹果safari浏览器的最新安全策略所导致的,现时safari浏览器无论是否设置cookie为secure或使用https,都仅允许同一域名下的跨域异步操作,在Google Chrome和Firefox浏览器测试中不存在上述问题。将server (https://shop-api.wei.ai) 和client (https://shop.wei.ai) 部署到同一域名下后问题解决。